 /*******************************************************************************
  * Copyright (c) 2005, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.core.internal.runtime;

 import java.net.URL ;
 import java.util.*;
 import org.eclipse.core.internal.boot.PlatformURLBaseConnection;
 import org.eclipse.core.internal.boot.PlatformURLHandler;
 import org.eclipse.core.runtime.IAdapterManager;
 import org.eclipse.osgi.framework.log.FrameworkLog;
 import org.eclipse.osgi.service.datalocation.Location;
 import org.eclipse.osgi.service.debug.DebugOptions;
 import org.eclipse.osgi.service.localization.BundleLocalization;
 import org.eclipse.osgi.service.urlconversion.URLConverter;
 import org.osgi.framework.*;
 import org.osgi.service.packageadmin.PackageAdmin;
 import org.osgi.service.url.URLConstants;
 import org.osgi.service.url.URLStreamHandlerService;
 import org.osgi.util.tracker.ServiceTracker;

 /**
  * The Common runtime plugin class.
  *
  * This class can only be used if OSGi plugin is available.
  */
 public class Activator implements BundleActivator {

     /**
      * Table to keep track of all the URL converter services.
      */
     private static Map urlTrackers = new HashMap();
     private static BundleContext bundleContext;
     private static Activator singleton;
     private ServiceRegistration platformURLConverterService = null;
     private ServiceRegistration adapterManagerService = null;
     private ServiceTracker installLocationTracker = null;
     private ServiceTracker instanceLocationTracker = null;
     private ServiceTracker configLocationTracker = null;
     private ServiceTracker bundleTracker = null;
     private ServiceTracker debugTracker = null;
     private ServiceTracker logTracker = null;
     private ServiceTracker localizationTracker = null;

     /*
      * Returns the singleton for this Activator. Callers should be aware that
      * this will return null if the bundle is not active.
      */
     public static Activator getDefault() {
         return singleton;
     }

     /**
      * Print a debug message to the console.
      * Pre-pend the message with the current date and the name of the current thread.
      */
     public static void message(String message) {
         StringBuffer buffer = new StringBuffer ();
         buffer.append(new Date(System.currentTimeMillis()));
         buffer.append(" - ["); //$NON-NLS-1$
 buffer.append(Thread.currentThread().getName());
         buffer.append("] "); //$NON-NLS-1$
 buffer.append(message);
         System.out.println(buffer.toString());
     }

     /* (non-Javadoc)
      * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
      */
     public void start(BundleContext context) throws Exception {
         bundleContext = context;
         singleton = this;
         Dictionary urlProperties = new Hashtable();
         urlProperties.put("protocol", "platform"); //$NON-NLS-1$ //$NON-NLS-2$
 platformURLConverterService = context.registerService(URLConverter.class.getName(), new PlatformURLConverter(), urlProperties);
         adapterManagerService = context.registerService(IAdapterManager.class.getName(), AdapterManager.getDefault(), null);
         installPlatformURLSupport();
     }

     /*
      * Return the configuration location service, if available.
      */
     public Location getConfigurationLocation() {
         if (configLocationTracker == null) {
             Filter filter = null;
             try {
                 filter = bundleContext.createFilter(Location.CONFIGURATION_FILTER);
             } catch (InvalidSyntaxException e) {
                 // should not happen
 }
             configLocationTracker = new ServiceTracker(bundleContext, filter, null);
             configLocationTracker.open();
         }
         return (Location) configLocationTracker.getService();
     }

     /*
      * Return the debug options service, if available.
      */
     public DebugOptions getDebugOptions() {
         if (debugTracker == null) {
             debugTracker = new ServiceTracker(bundleContext, DebugOptions.class.getName(), null);
             debugTracker.open();
         }
         return (DebugOptions) debugTracker.getService();
     }

     /*
      * Return the framework log service, if available.
      */
     public FrameworkLog getFrameworkLog() {
         if (logTracker == null) {
             logTracker = new ServiceTracker(bundleContext, FrameworkLog.class.getName(), null);
             logTracker.open();
         }
         return (FrameworkLog) logTracker.getService();
     }

     /*
      * Return the instance location service, if available.
      */
     public Location getInstanceLocation() {
         if (instanceLocationTracker == null) {
             Filter filter = null;
             try {
                 filter = bundleContext.createFilter(Location.INSTANCE_FILTER);
             } catch (InvalidSyntaxException e) {
                 // ignore this. It should never happen as we have tested the above format.
 }
             instanceLocationTracker = new ServiceTracker(bundleContext, filter, null);
             instanceLocationTracker.open();
         }
         return (Location) instanceLocationTracker.getService();
     }

     /**
      * Return the resolved bundle with the specified symbolic name.
      *
      * @see PackageAdmin#getBundles(String, String)
      */
     public Bundle getBundle(String symbolicName) {
         PackageAdmin admin = getBundleAdmin();
         if (admin == null)
             return null;
         Bundle[] bundles = admin.getBundles(symbolicName, null);
         if (bundles == null)
             return null;
         //Return the first bundle that is not installed or uninstalled
 for (int i = 0; i < bundles.length; i++) {
             if ((bundles[i].getState() & (Bundle.INSTALLED | Bundle.UNINSTALLED)) == 0) {
                 return bundles[i];
             }
         }
         return null;
     }

     /*
      * Return the package admin service, if available.
      */
     private PackageAdmin getBundleAdmin() {
         if (bundleTracker == null) {
             bundleTracker = new ServiceTracker(getContext(), PackageAdmin.class.getName(), null);
             bundleTracker.open();
         }
         return (PackageAdmin) bundleTracker.getService();
     }

     /*
      * Return an array of fragments for the given bundle host.
      */
     public Bundle[] getFragments(Bundle host) {
         PackageAdmin admin = getBundleAdmin();
         if (admin == null)
             return new Bundle[0];
         return admin.getFragments(host);
     }

     /*
      * Return the install location service if available.
      */
     public Location getInstallLocation() {
         if (installLocationTracker == null) {
             Filter filter = null;
             try {
                 filter = bundleContext.createFilter(Location.INSTALL_FILTER);
             } catch (InvalidSyntaxException e) {
                 // should not happen
 }
             installLocationTracker = new ServiceTracker(bundleContext, filter, null);
             installLocationTracker.open();
         }
         return (Location) installLocationTracker.getService();
     }

     /**
      * Returns the bundle id of the bundle that contains the provided object, or
      * <code>null</code> if the bundle could not be determined.
      */
     public String getBundleId(Object object) {
         if (object == null)
             return null;
         if (bundleTracker == null) {
             message("Bundle tracker is not set"); //$NON-NLS-1$
 return null;
         }
         PackageAdmin packageAdmin = (PackageAdmin) bundleTracker.getService();
         if (packageAdmin == null)
             return null;

         Bundle source = packageAdmin.getBundle(object.getClass());
         if (source != null && source.getSymbolicName() != null)
             return source.getSymbolicName();
         return null;
     }

     public ResourceBundle getLocalization(Bundle bundle, String locale) {
         if (localizationTracker == null) {
             BundleContext context = Activator.getContext();
             if (context == null) {
                 message("ResourceTranslator called before plugin is started"); //$NON-NLS-1$
 return null;
             }
             localizationTracker = new ServiceTracker(context, BundleLocalization.class.getName(), null);
             localizationTracker.open();
         }
         BundleLocalization location = (BundleLocalization) localizationTracker.getService();
         if (location != null)
             return location.getLocalization(bundle, locale);

         return null;
     }

     /* (non-Javadoc)
      * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
      */
     public void stop(BundleContext context) throws Exception {
         closeURLTrackerServices();
         if (platformURLConverterService != null) {
             platformURLConverterService.unregister();
             platformURLConverterService = null;
         }
         if (adapterManagerService != null) {
             adapterManagerService.unregister();
             adapterManagerService = null;
         }
         if (installLocationTracker != null) {
             installLocationTracker.close();
             installLocationTracker = null;
         }
         if (configLocationTracker != null) {
             configLocationTracker.close();
             configLocationTracker = null;
         }
         if (bundleTracker != null) {
             bundleTracker.close();
             bundleTracker = null;
         }
         if (debugTracker != null) {
             debugTracker.close();
             debugTracker = null;
         }
         if (logTracker != null) {
             logTracker.close();
             logTracker = null;
         }
         if (instanceLocationTracker != null) {
             instanceLocationTracker.close();
             instanceLocationTracker = null;
         }
         if (localizationTracker != null) {
             localizationTracker.close();
             localizationTracker = null;
         }
         bundleContext = null;
         singleton = null;
     }

     /*
      * Return this bundle's context.
      */
     static BundleContext getContext() {
         return bundleContext;
     }

     /*
      * Let go of all the services that we acquired and kept track of.
      */
     private static void closeURLTrackerServices() {
         synchronized (urlTrackers) {
             if (!urlTrackers.isEmpty()) {
                 for (Iterator iter = urlTrackers.keySet().iterator(); iter.hasNext();) {
                     String key = (String ) iter.next();
                     ServiceTracker tracker = (ServiceTracker) urlTrackers.get(key);
                     tracker.close();
                 }
                 urlTrackers = new HashMap();
             }
         }
     }

     /*
      * Return the URL Converter for the given URL. Return null if we can't
      * find one.
      */
     public static URLConverter getURLConverter(URL url) {
         String protocol = url.getProtocol();
         synchronized (urlTrackers) {
             ServiceTracker tracker = (ServiceTracker) urlTrackers.get(protocol);
             if (tracker == null) {
                 // get the right service based on the protocol
 String FILTER_PREFIX = "(&(objectClass=" + URLConverter.class.getName() + ")(protocol="; //$NON-NLS-1$ //$NON-NLS-2$
 String FILTER_POSTFIX = "))"; //$NON-NLS-1$
 Filter filter = null;
                 try {
                     filter = getContext().createFilter(FILTER_PREFIX + protocol + FILTER_POSTFIX);
                 } catch (InvalidSyntaxException e) {
                     return null;
                 }
                 tracker = new ServiceTracker(getContext(), filter, null);
                 tracker.open();
                 // cache it in the registry
 urlTrackers.put(protocol, tracker);
             }
             return (URLConverter) tracker.getService();
         }
     }

     /**
      * Register the platform URL support as a service to the URLHandler service
      */
     private void installPlatformURLSupport() {
         PlatformURLPluginConnection.startup();
         PlatformURLFragmentConnection.startup();
         PlatformURLMetaConnection.startup();
         PlatformURLConfigConnection.startup();

         Location service = getInstallLocation();
         if (service != null)
             PlatformURLBaseConnection.startup(service.getURL());

         Hashtable properties = new Hashtable(1);
         properties.put(URLConstants.URL_HANDLER_PROTOCOL, new String [] {PlatformURLHandler.PROTOCOL});
         getContext().registerService(URLStreamHandlerService.class.getName(), new PlatformURLHandler(), properties);
     }

 }

